<template>
  <div class="jax-transparent">
    <input type="file" class="jax-transparent-input" @change="handleUpload" v-bind="inputAttr" />
    <slot name="input-before"></slot>
    <slot name="input">
      <el-button type="primary" icon="upload">点击上传</el-button>
    </slot>
    <slot name="input-after"></slot>
  </div>
</template>

<script>
// import axios from 'axios'

export default {
  name: 'JaxInputFile',
  props: {
    // v-model
    modelValue: Array,

    // input原生属性
    inputAttr: Object,

    // 上传文件的字段名
    fieldname: {
      type: String,
      default: 'files',
    },

    // 上传数量 0、不限制
    limit: 0,

    // 上传地址
    url: {
      type: String,
      default: '/upload',
    },

    // header
    headers: {
      type: Object,
      default: {},
    },

    // 上传提示
    loading: {
      default: '上传中...',
    },

    // 上传前
    beforeUpload: Function,

    // 上传过程中
    uploadProgress: Function,

    // 上传成功
    uploadSuccess: Function,
  },
  data() {
    return {
      index: 0,
      fileList: [],
    }
  },
  computed: {
    // 是否多选
    multiple() {
      return this.inputAttr && this.inputAttr.multiple
    },
  },
  watch: {
    modelValue() {
      this.init()
    },
  },
  created() {
    this.init()
  },

  methods: {
    init() {
      this.fileList = this.modelValue || []
    },

    handleUpload(e) {
      this.upload(e.target.files)

      // 解决连续选择同一个文件
      e.target.value = null
    },

    upload(files) {
      const { limit } = this

      if (limit && files.length + this.fileList.length > limit) {
        return this.$message.error(`最多上传${limit}个文件`)
      }

      for (let i = 0; i < files.length; i++) {
        this.send(files[i])
      }
    },

    send(file) {
      const formData = new FormData()

      formData.append(this.fieldname, file)

      // 上传前
      if (this.beforeUpload) {
        var result = this.beforeUpload(file)

        if (result == false) return
      }

      //   let config = {
      //     headers: { 'Content-Type': 'multipart/form-data' },
      //     showLoading: '上传中...',
      //   };

      const returnFile = {
        index: this.index++,
        status: 'ready',
        name: file.name,
        size: file.size,
        percentage: 0,
        file: window.URL.createObjectURL(file),
      }

      // 支持文件多选
      if (this.multiple) {
        const data = this.fileList
        data.push(returnFile)
        this.$emit('update:modelValue', data)
      } else {
        this.$emit('update:modelValue', [returnFile])
      }

      const index = this.fileList && this.fileList.length ? this.fileList.length - 1 : 0

      this.$http({
        method: 'post',
        url: this.url,
        data: formData,
        onUploadProgress: (progressEvent) => {
          const percentage = ((progressEvent.loaded / progressEvent.total) * 100).toFixed(2)

          this.updateFiles(index, {
            percentage: percentage > 99 ? 99 : percentage,
            status: 'uploading',
          })

          this.uploadProgress && this.uploadProgress(progressEvent)
        },
        headers: this.headers,
        // showLoading: this.loading,
        // headers: { 'Content-Type': 'multipart/form-data' },
      })
        .then((res) => {
          this.updateFiles(index, {
            ...res[0],
            percentage: 100,
            status: 'success',
          })

          // 上传完成
          this.uploadSuccess && this.uploadSuccess(res)
        })
        .catch((error) => {
          this.updateFiles(index, {
            status: 'fail',
            error: error,
            percentage: 100,
          })
        })
    },

    // 更新上传文件信息
    updateFiles(index, data) {
      const fileList = [...this.fileList]
      fileList[index] = {
        ...this.fileList[index],
        ...data,
      }

      this.$emit('update:modelValue', fileList)
    },
  },
}
</script>

<style scoped lang="scss">
.jax-transparent {
  position: relative;
  width: fit-content;
}

.jax-transparent-input {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  height: 100%;
  width: 100%;
  z-index: 1;
  cursor: pointer;
}
</style>
